package org.NooLab.glue.subscription.context;

import java.io.Serializable;
import java.util.Arrays;

import org.NooLab.glue.subscription.MessageMatcher;


/**
 * <p>
 * This class represents the structure of a context. 
 * No methods for comparing 2 contexts are included !
 * 
 * For controlling fine-grained approximate matching of messages and subscriptions. <p/><p>
 * Basically, the MessageBoard does not know anything about the content of the data object that is
 * included in the message. Thus, in order to use the subscription mechanism, any message provider
 * has to define some more open criteria that can be used for the matching.<p/><p>
 * 
 * There are two styles of defining such criteria, a plain and a context style. While the plain style
 * is just a single set of items with some matching threshold, the context allows for much more
 * differentiated definition of a match.<p/><p>
 * 
 * This class addresses two very different use cases: (1) context defined as a pattern in a text, and
 * (2) context as a set of items that are interpreted as a feature vector. 
 * 
 * <p/><p> 
 * 
 * It defines some measures and criteria to decide whether a particular 
 * transaction passing through the MessageBoard should be relayed to the
 * subscriber or not </p>
 * 
 * According to the definition, a context comprises 1 or several sets of items,
 * plus some numerical thresholding criteria reflecting aspects of completeness
 * and "density".
 * 
 * From all item sets the "mandatorySet" is the only mandatory one.
 * In total, there are 5 different item sets:
 * <ul><li>mandatorySet : any missing element from this causes a denial of the match</li>
 * <li>normalSet &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: items from this set can be weighted in their contribution to the positive part of the definition</li>
 * <li>facultativeSet : does not contribute to the positive match, but it helps to avoid denial due to insertions </li>
 * <li>competingSet &nbsp;: if this is more similar than mandatory and normal, the match is denied</li>
 * <li>excludingSet &nbsp;&nbsp;: any item from this set denies the match</li>
 * </ul></br>
 * 
 * The actual pattern matching for contexts is performed in the class {@link MessageMatcher}
 */
public class Context implements ContextIntf, Serializable{
 
	private static final long serialVersionUID = 4175458367756424525L;
	
	// =================================

	// object references ..............

	

	
	// main variables / properties ....

	String label = "";
	
	/** just info=0, plain=1, or complete=2;</br>
	 *  if "just info", the matching is completely on the side of the subscriber,
	 *  if "plain"+ then the issuer may provide 
	 */
	int contextStyle = ContextInfra._CSTYL_JUSTINFO;
	
	// items=0, feature vector=1
	int dataType = ContextInfra._DTYP_ITEMS ;    
	
	
	/** the role describes SOURCE, RECEPTOR or BOARD, i.e. restricting the matching by this information
	 *  allows to select from messages according to their originators : messages by SOURCEs are tasks,
	 *  those by RECEPTORs are results */
	String roleOfIssuer = "*";  
	/** "personalization" of context matching */
	String nameOfIssuer = "*";  
	
	boolean disclosureAllowData  = false;
	boolean disclosureAllowName  = false ;
	boolean clientRelayByContext = false ;
	
	
	String[] itemSet = new String[0] ;
	 
	/** percentage of items allowed to be missing, and the context is still recognized; 
	 *  items from the mandatory set count 1, while for those of the normal set the weight will apply */
	double missingItems; 
	/** percentage of items found in a segment that are not part of the definition of the context */
	double enlargement;
	/** the largest accepted ratio of observed pattern and the size of given positive definitions (mandatory, normal)*/
	double lengthRatio;
	/** the largest accepted segment in an observation consisting from items in a single row that are not part of the definition  */
	double insertionLength ;
	
	/** a value between [0,1], that applies if the observation fulfills all excluding rules */
	double minimalMatch;
	/** the weights for the normal items */
	double[] weightsNormalItems;
	 
	 
	/**    */
	String[] mandatorySet ;
	/**    */
	String[] normalSet = new String[0] ;
	/**    */
	String[] facultativeSet = new String[0] ;
	/**    */
	String[] competingSet = new String[0] ;
	/**    */
	String[] excludingSet = new String[0] ;
	
	
	boolean contextComplete = false;
	
	/** will be used as soon as there is more than 0 entries */
	String[] featureSet = new String[0] ;
	/** item values are facultative, but if they are given, care about the alignment to the feature set;
	 *  else if itemValues are provided you also should define a threshold for the similarity 
	 *  itemValues should be scaled  to values from [0..1] */
	double[] featureValues = new double[0];
	double similaryMatchingThreshold = -1;
	
	String fullText ;
	
	
	// volatile variables .............
	transient int cdim=0;
	
	
	// helper objects .................
	 


	// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
	public Context(){
		cdim = 0;
	}
	
	// simple clone
	public Context( ContextIntf templatedContext ){
		Context ctxt = ((Context)templatedContext);
		
		itemSet = ctxt.itemSet ;
		label = ctxt.label;
		
		// TODO complete it
	}
	// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

	
	private void checkForCompleteness(){
		contextComplete = cdim>=3 ;
	}
	
	
	/**
	 * This defines a context that behaves like the PLAIN style 
	 * 
	 * @param label
	 * @param itemset
	 */
	public void addParameters( String label, String[] itemset, double matchingThreshold){
		
		cdim = cdim + 1;
		
		try{
		
			this.label = label;
			itemSet = Arrays.copyOf( itemset,itemset.length ) ;
			
			minimalMatch = matchingThreshold;
			
			checkForCompleteness();
		}catch(Exception e){
		}
		
	
	}
	
	


	/**
	 * Context Info : image as byte array, it is assumed to be a jpg/jpeg
	 * 
	 * @param label
	 * @param itemset
	 * 
	 */
	public void addDescribingParameters( String label, byte[] image ){
		
		try{
			
			setContextStyle(ContextInfra._CSTYL_JUSTINFO);
			setDataType( ContextInfra._DTYP_BINIMG );
		
			this.label = label;
			
			 
		}catch(Exception e){
		}
	}
	
		

	/**
	 * Context Info : text, e.g. a summary or other kind of extract
	 * 
	 * @param label
	 * @param itemset
	 */
	public void addDescribingParameters( String label, String text ){
		
		try{
			
			setContextStyle(ContextInfra._CSTYL_JUSTINFO);
			setDataType( ContextInfra._DTYP_FULLTEXT );
		
			this.label = label;
			
			 
		}catch(Exception e){
		}
	}
	
		
		
	/**
	 * Context Info : item set
	 * 
	 * @param label
	 * @param itemset
	 */
	public void addDescribingParameters( String label, String[] itemset, double requiredMinSimilarity){
		
		 
		
		try{
			
			setContextStyle(ContextInfra._CSTYL_JUSTINFO);
			setDataType( ContextInfra._DTYP_ITEMS );
		
			this.label = label;
			itemSet = Arrays.copyOf( itemset,itemset.length ) ;
			 
		}catch(Exception e){
		}
		
	}
	
	/**
	 * 
	 * Context Info : feature vector with values for competitive routing based on similarity
	 * 
	 * @param label
	 * @param features
	 * @param values
	 * @throws Exception
	 */
	public void addDescribingParameters( String label, String[] features, double[] values, double requiredMinSimilarity) throws Exception{
	
		addDescribingParameters( label,features, values, new String[]{}, requiredMinSimilarity) ;
	}
	
	public void addDescribingParameters( String label, String[] features, double[] values, String[] exclfeatures , double requiredMinSimilarity) throws Exception{

		try{
		
			if ((features.length==0) || (features.length != values.length)){
				throw(new Exception("definition of feature vector incorrect: unequal lengths."));
			}
			
			setContextStyle(ContextInfra._CSTYL_JUSTINFO);
			setDataType( ContextInfra._DTYP_FVECTOR );
			
			this.label = label;
			
			featureSet = Arrays.copyOf( features, features.length ) ;
			featureValues = Arrays.copyOf( values, values.length ) ;
			
			if ( (exclfeatures!=null) && (exclfeatures.length>0)){
				excludingSet = Arrays.copyOf( exclfeatures, exclfeatures.length ) ;	
			}
			
			
		}catch(Exception e){
		}
		
	}
	
	
	/**
	 * 
	 *  missing items, thinning item group , length, distances between elements  _MIXES
	 *  
	 
	 * @param missingItems
	 * @param enlargement
	 * @param lengthratio
	 * @param insLength
	 */
	public void addParameters( double missingitems, double enlargement, double lengthratio, double insLength ){
		 
		
		try{
		
			cdim = cdim + 1;
			
			missingItems = missingitems ; 
			this.enlargement = enlargement ;
			lengthRatio = lengthratio ;
			insertionLength = insLength  ;
			
			checkForCompleteness();
		}catch(Exception e){
		}

	}



	
	/**
	 * 
	 *  
	 * 
	 */
	public void addParameters(  double[] weigths ){
	 
		
		try{
			
			cdim = cdim + 1;
			
			
			this.weightsNormalItems = Arrays.copyOf( weigths,weigths.length ) ;
			
			checkForCompleteness();
		}catch(Exception e){
		}

	}
	
	
	/**
	 * 
	 * 
	 * @param cdim = _SETS
	 * @param setType
	 * @param items
	 */
	public void addParameters( int setType, String[] items  ){

		
		try{
			if (setType== ContextInfra._SET_MANDATORY){
				mandatorySet = Arrays.copyOf( items,items.length ) ;
			}
			if (setType== ContextInfra._SET_NORMAL){
				normalSet = Arrays.copyOf( items,items.length ) ;
			}
			if (setType== ContextInfra._SET_FACULTATIVE){
				facultativeSet = Arrays.copyOf( items,items.length ) ;
			}
			if (setType== ContextInfra._SET_COMPETING){
				competingSet = Arrays.copyOf( items,items.length ) ;
			}
			if (setType== ContextInfra.	_SET_EXCLUDING){
				excludingSet = Arrays.copyOf( items,items.length ) ;
			}
 
			 
		}catch(Exception e){
		}

		
	}
	
	@Override
	public void setPersonalization(String roleofissuer, String nameofissuer) {

		roleOfIssuer = roleofissuer;  
		
		nameOfIssuer = nameofissuer;  
		
	}
	
	// ------------------------------------------------------------------------



	public String getLabel() {
		return label;
	}



	public void setLabel(String label) {
		this.label = label;
	}



	public int getContextStyle() {
		return contextStyle;
	}


	public void setContextStyle(int contextStyle) {
		this.contextStyle = contextStyle;
	}


	public int getDataType() {
		return dataType;
	}


	public void setDataType(int dataType) {
		this.dataType = dataType;
	}


	public String[] getItemSet() {
		return itemSet;
	}



	public void setItemSet(String[] itemSet) {
		this.itemSet = itemSet;
	}



	public double getMissingItems() {
		return missingItems;
	}



	public void setMissingItems(double missingItems) {
		this.missingItems = missingItems;
	}



	public double getEnlargement() {
		return enlargement;
	}



	public void setEnlargement(double enlargement) {
		this.enlargement = enlargement;
	}



	public double getLengthRatio() {
		return lengthRatio;
	}



	public void setLengthRatio(double lengthRatio) {
		this.lengthRatio = lengthRatio;
	}



	public double getInsertionLength() {
		return insertionLength;
	}



	public void setInsertionLength(double insertionLength) {
		this.insertionLength = insertionLength;
	}



	public double getMinimalMatch() {
		return minimalMatch;
	}



	public void setMinimalMatch(double minimalMatch) {
		this.minimalMatch = minimalMatch;
	}


	
	public double[] getWeightsOfNormalItems() {
		return weightsNormalItems;
	}



	public void setWeightsOfNormalItems(double[] weigths) {
		this.weightsNormalItems = weigths;
	}



	public String[] getMandatorySet() {
		return mandatorySet;
	}



	public void setMandatorySet(String[] mandatorySet) {
		this.mandatorySet = mandatorySet;
	}



	public String[] getNormalSet() {
		return normalSet;
	}



	public void setNormalSet(String[] normalSet) {
		this.normalSet = normalSet;
	}



	public String[] getFacultativeSet() {
		return facultativeSet;
	}



	public void setFacultativeSet(String[] facultativeSet) {
		this.facultativeSet = facultativeSet;
	}



	public String[] getCompetingSet() {
		return competingSet;
	}



	public void setCompetingSet(String[] competingSet) {
		this.competingSet = competingSet;
	}



	public String[] getExcludingSet() {
		return excludingSet;
	}



	public void setExcludingSet(String[] excludingSet) {
		this.excludingSet = excludingSet;
	}



	public boolean contextIsComplete() {
		return contextComplete;
	}

	
	public boolean isContextComplete() {
		return contextComplete;
	}



	public void setContextComplete(boolean contextComplete) {
		this.contextComplete = contextComplete;
	}


	public String getRoleOfIssuer() {
		return roleOfIssuer;
	}


	public String getNameOfIssuer() {
		return nameOfIssuer;
	}


	public double[] getWeightsNormalItems() {
		return weightsNormalItems;
	}


	public String[] getFeatureSet() {
		return featureSet;
	}


	 

	public double[] getFeatureValues() {
		return featureValues;
	}


	public void setFeatureValues(double[] featureValues) {
		this.featureValues = featureValues;
	}


	public String getFullText() {
		return fullText;
	}

	public void setFullText(String fullText) {
		this.fullText = fullText;
	}

	public double getSimilaryMatchingThreshold() {
		return similaryMatchingThreshold;
	}


	public void setRoleOfIssuer(String roleOfIssuer) {
		this.roleOfIssuer = roleOfIssuer;
	}


	public void setNameOfIssuer(String nameOfIssuer) {
		this.nameOfIssuer = nameOfIssuer;
	}


	public void setWeightsNormalItems(double[] weightsNormalItems) {
		this.weightsNormalItems = weightsNormalItems;
	}


	public void setFeatureSet(String[] featureSet) {
		this.featureSet = featureSet;
	}

 


	public void setSimilaryMatchingThreshold(double similaryMatchingThreshold) {
		this.similaryMatchingThreshold = similaryMatchingThreshold;
	}


	public boolean isClientRelayByContext() {
		return clientRelayByContext;
	}
	public boolean getClientRelayByContext() {
		return clientRelayByContext;
	}


	public void setClientRelayByContext(boolean clientRelayByContext) {
		this.clientRelayByContext = clientRelayByContext;
	}


	public boolean isAllowDataDisclosure() {
		return disclosureAllowData;
	}
	public boolean getDisclosureAllowData() {
		return disclosureAllowData;
	}

	public void setDisclosureAllowData(boolean allowData) {
		this.disclosureAllowData = allowData;
	}
	public boolean isDisclosureAllowName() {
		return disclosureAllowName;
	}
	public boolean getDisclosureAllowName() {
		return disclosureAllowName;
	}
	public void setDisclosureAllowName(boolean allowName) {
		this.disclosureAllowName = allowName;
	}

	 
	
	
	
}
